/*
 * StatisticsManager.cpp
 *
 *      Author: Jerome RD Soine and Christoph A Brand
 *      Institution: Schwarz goup, Institute for Theoretical Physics, Heidelberg University, Germany
 */


#include "StatisticsManager.h"
#include <include/core/utility/VectorOperations.h>
#include <fstream>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

StatisticsManager::StatisticsManager(string FILENAME, unsigned int NBINS)
{
	vector<double> value_list = read_value_list(FILENAME);
	norm_distribution = generate_distribution(value_list,NBINS);
	n_bins = NBINS;
	srand (time(NULL));
}

vector<double> StatisticsManager::read_value_list(string FILENAME)
{
	// READ VALUES FROM SINGLE COLUMN
	double tmp;
	vector<double> value_list;
	ifstream input (FILENAME.c_str());
	if(input.good())
	{
		while(!input.eof())
		{
			input >> tmp;
			value_list.push_back(tmp);
		}
	}
	else
	{
		cout << "ERROR: with file " << FILENAME << " -> no such file or directory." << endl;
		exit(1);
	}
	input.close();
	return value_list;

}

vector<vector<double> > StatisticsManager::generate_distribution(vector<double> value_list, unsigned int n_bins)
{
	double min_value = VectorOperations::get_min_component(value_list);
	double max_value = VectorOperations::get_max_component(value_list);
	unsigned int total_number = value_list.size()-1;
	cout << "Total Number of values = " << total_number << endl;
	vector<vector<double> > dist;
	double bin_size = (max_value-min_value)/(double)n_bins;
	double total_prob = 0;
	for(unsigned int i=0;i<n_bins;i++)
	{
		vector<double> tmp_vec;
		tmp_vec.push_back(i*bin_size);
		tmp_vec.push_back((i+1)*bin_size);
		unsigned int tmp_frequency = 0;
		for(unsigned int j=0;j<value_list.size();j++)
		{
			if(value_list[j]>=tmp_vec[0] && value_list[j]<tmp_vec[1])
				tmp_frequency++;
		}
		tmp_vec.push_back((double)tmp_frequency/(double)total_number);
		total_prob+=(double)tmp_frequency/(double)total_number;
		tmp_vec.push_back(total_prob);
		dist.push_back(tmp_vec);
	}
	cout << "TOTAL PROB = " << total_prob << endl;
	return dist;
}

double StatisticsManager::pick_values_from_distribution()
{
	// Generate value between 0 and 1
	double p = (double)rand()/RAND_MAX;

	// Search for right bin within normal distribution
	for (unsigned int i = 0; i < n_bins; ++i) {
		if(p<=norm_distribution[i][3]){
			p = (double)rand()/RAND_MAX;
			return p*(norm_distribution[i][1]-norm_distribution[i][0]) + norm_distribution[i][0];
		}
	}
	cout << "ERROR: in StatisticsManagaer - PICKED VALUE OUT OF RANGE \n";
	exit(1);
}

double StatisticsManager::get_binned_probability(double value)
{
	for (unsigned int i = 0; i < n_bins; ++i) {
		if(value >= norm_distribution[i][0] && value < norm_distribution[i][1])
			return norm_distribution[i][2];
	}
	cout << "ERROR: VALUE IS NOT IN RANGE OF DISTRIBUTION" << endl;
	return 0.0;
}
